/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/

#include "uartps.h"

static XUartPsFormat uart_format =
{
	UART_BAUDRATE,
	UART_DATA_BITS,
	UART_PARITY_BIT,
	UART_STOP_BIT,
};


int UartPsInitial(XUartPs *UartInstPtr,u16 DeviceId)
{
	int Status;
	XUartPs_Config *Config;

	Config = XUartPs_LookupConfig(DeviceId);
	if (NULL == Config) {
		return XST_FAILURE;
	}

	Status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Check hardware build */
	Status = XUartPs_SelfTest(UartInstPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	Status = XUartPs_SetDataFormat(UartInstPtr, &uart_format);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}



/***************************************************************************//**
 * @brief Writes one character to UART.
 *
 * @param data - Character to write.
 *
 * @return None.
*******************************************************************************/
void uart_send_char(char data)
{
	putchar(data);
}

/***************************************************************************//**
 * @brief Reads one character from UART.
 *
 * @return received_char   - Read character.
 *
 * Note: Blocking function - Waits until get a valid data.
*******************************************************************************/
void uart_recv_char(char * data)
{
	*data = getchar();
}

/***************************************************************************//**
 * @brief Writes one character string to UART.
 *
 * @param data - Character to write.
 *
 * @return None.
*******************************************************************************/
void uart_send_string(char* string)
{
	char		  write_char 	= 0;
	unsigned char char_number	= 0;

	while((write_char != '\n')&&(write_char != '\r'))
	{
		write_char = string[char_number];
		uart_send_char(write_char);
		char_number++;
	}
}


/***************************************************************************//**
 * @brief Reads one command from console.
 *
 * @param command - Read command.
 *
 * @return None.
*******************************************************************************/
void uart_recv_string(char* string)
{
	char		  read_char		= 0;
	unsigned char char_number	= 0;

	while((read_char != '\n') && (read_char != '\r'))
	{
		uart_recv_char(&read_char);
		string[char_number] = read_char;
		char_number++;
	}
}


int uartps_echo(char *data_buffer)
{

	xil_printf("UartPs waiting for input...\r\n");

	while(1)
	{
		uart_recv_string(data_buffer);
		uart_send_string(data_buffer);
	}
	return 0;
}

int char_to_hex(char *char_buffer, unsigned int *hex_buffer, u8 size_buf, u8 hex_len)
{
	const char digits[16]="0123456789ABCDEF";
	u8 byte_index=0;
	u8 char_index=0;
	u8 digit_index=0;
	unsigned int digit_buffer[size_buf];
	memset(digit_buffer,0,sizeof(digit_buffer));

	while(char_buffer[char_index]!='\n' && char_buffer[char_index]!='\r')
	{
		if(char_buffer[char_index]==' '){
			char_index++;
			continue;
		}
		for(digit_index = 0; digit_index < 16; digit_index++)
		{
			if(char_buffer[char_index] == digits[digit_index])
			{
				digit_buffer[byte_index++] = digit_index;
				break;
			}
		}
		if(digit_index>=16)//not hex data
		{
			return 1;
		}
		char_index++;
	}

	hex_group(digit_buffer,hex_buffer,size_buf,hex_len);
	return 0;
}

void hex_group(unsigned int *data_buffer, unsigned int *hex_buffer,  u8 size_buf, u8 hex_len)
{
	u8  bytes_index=0;
	u8  digit_index=0;
	u8  hex_index=0;
	unsigned int hex_value=0;
	//char[A,B,C,D...] -> hex[0xAB,0xCD...]
	while(hex_index<size_buf)
	{
		for(digit_index = 0; digit_index < hex_len; digit_index++)
		{
			hex_value += data_buffer[bytes_index+digit_index] * pow(16,(hex_len-1-digit_index));
		}

		bytes_index += hex_len;
		hex_buffer[hex_index++]=hex_value;
		hex_value=0;
	}
}

void hex_ungroup(unsigned int *data_buffer,u8 *hex_buffer, u8 byte_len, u8 hex_len)
{
	u8  digit_index=0;
	u8  hex_index=0;
	unsigned int hex_temp=0;
	unsigned int hex_value=0;
	//hex[0xAB,0xCD...] -> char[A,B,C,D...]
	while(hex_index<byte_len)
	{
		for(digit_index = 0; digit_index < hex_len; digit_index++)
		{
			hex_temp = (unsigned int)hex_buffer[hex_index];
			hex_value = (hex_temp>>(4*(hex_len-1-digit_index)))&0xF;
			data_buffer[hex_index*hex_len+digit_index]=hex_value;
		}
		hex_index++;
	}
}

int hex_to_char(char *char_buffer, u8 *hex_buffer, u8 byte_len, u8 hex_len)
{
	const char digits[16]="0123456789ABCDEF";
	u8 char_index=0;
	u8 digit_index=0;
	unsigned int digit_buffer[byte_len*2];
	memset(digit_buffer,0,sizeof(digit_buffer));

	hex_ungroup(digit_buffer,hex_buffer,byte_len,hex_len);

	while(char_index<byte_len*2)
	{
		for(digit_index = 0; digit_index < 16; digit_index++)
		{
			if(digit_buffer[char_index] == digit_index)
			{
				char_buffer[char_index] = digits[digit_index];
				break;
			}
		}
		if(digit_index>=16)//not hex data
		{
			return 1;
		}
		char_index++;
	}
	return 0;
}
